"""
闭包和装饰器
"""

"""
1.闭包
    闭包指的是有权访问另一个函数作用域中的变量的函数。即使该外部函数已经执行完毕，内部函数依旧能够访问其作用域内的变量。以下是闭包的构成条件：
1.存在一个嵌套函数。
2.嵌套函数引用了外部函数的变量。
3.外部函数返回嵌套函数

闭包的应用场景包括:
1.保护私有变量:可以使用闭包来创建私有变量和方法，通过内部函数的作用域和环境变量，可以实现对外部访问的限制。
2.延迟执行:可以使用闭包来延迟某个函数的执行，即在函数外部创建一个闭包，将需要执行的函数作为内部函数，通过调用闭包来触发函数的执行。
3.缓存数据:可以使用闭包来缓存一些昂贵的计算结果，以避免重复计算，提高程序的性能。
需要注意的是，在使用闭包时，要注意管理内存，避免产生不必要的内存泄漏问题

"""
# 1.简单的闭包

def outer_function(x):
    def inner_function(y):
        return x + y
    return inner_function

closure = outer_function(10)
result = closure(5)
print(result)  # 输出 15

# outer_function 是外部函数，inner_function 是嵌套函数。inner_function 引用了外部函数的变量 x。outer_function 返回了 inner_function，这样 closure 就变成了一个闭包。
# 当调用 closure(5) 时，它会把外部函数的 x（值为 10）和传入的 y（值为 5）相加，最后得到 15。

# 2.nonlocal
# 内部函数只能访问外部函数的局部变量，却不能直接对其进行修改。若要在内部函数中修改外部函数的局部变量，就得使用 nonlocal 关键字
def outer_function():
    count = 0
    def inner_function():
        nonlocal count
        count += 1
        return count
    return inner_function

counter = outer_function()
print(counter())  # 输出 1
print(counter())  # 输出 2
print(counter())  # 输出 3

# 外部函数 outer_function：定义了一个局部变量 count，其初始值为 0。同时返回了内部函数 inner_function。
# 内部函数 inner_function：使用 nonlocal 关键字声明 count，表明这个 count 并非 inner_function 的局部变量，而是外部函数 outer_function 的局部变量。接着对 count 进行自增操作，并返回 count 的值。
# 调用闭包：counter = outer_function() 得到一个闭包 counter。每次调用 counter() 时，count 的值都会增加



"""
2.装饰器
装饰器是一种特殊的函数，其作用是对其他函数say_hello函数进行扩展，却无需修改被装饰函数的源代码。
装饰器本质上就是一个闭包，它接收一个函数作为参数，并且返回一个新的函数

***带参数的装饰器（pytest数据驱动使用）
"""

# 1.简单装饰器
def my_decorator(func):
    def wrapper():
        print("在函数执行前做些事情")
        func()          # 内函数可以使用外函数的变量，只是这次外函数变量是一个函数
        print("在函数执行后做些事情")
    return wrapper

@my_decorator  # 相当于 say_hello =my_decorator (say_hello) = 间接等于return返回的wrapper
def say_hello():
    print("Hello!")

say_hello()     # 间接等于执行wrapper（）  也就是执行的内部函数

# my_decorator 是一个装饰器函数，它接收一个函数 func 作为参数，并且返回一个新的函数 wrapper。wrapper 函数会在调用 func 前后执行一些额外的操作。
# @my_decorator 这种语法糖的作用是把 say_hello 函数作为参数传递给闭包的外函数 my_decorator，
# 外函数执行后，返回内函数的引用，
# 再将内函数的引用赋值给被装饰函数 say_hello。
# 因此，当调用 say_hello() 时，实际上调用的是 wrapper() 函数。


# 2.通用装饰器
def decorator_args(func):
    def inner(*args,**kwargs):
        result = func(*args,**kwargs)
        return result
    return inner
@decorator_args
def show(a,b,c):
    print(a,b,c)

show(1,2,3)

# 3.带参数的装饰器（pytest数据驱动使用）
# 再通用装饰器基础上又包了一层
def decorator_args2(vars,datas):
    def decorator_args(func):
        def inner(*args,**kwargs):
            result = func(*args,**kwargs)
            return result
        return inner
    return decorator_args

data = [(1,2,3),(4,5,6),(7,8,9)],
@decorator_args2("majialu,巫明瑾",data)  # show2 = decorator_args2("majialu,巫明瑾",data) =间接等于decorator_args
def show2(a,b,c):
    print(a,b,c)




